---
title: DoesUserHaveResource
summary: Reports whether a user's authorization groups include a resource group matching the requested name.
status: draft
owner: "Not determined from source"
last_reviewed: 2026-09-22
---

# DoesUserHaveResource (OP-08)

## Request and response

| Part | Type | Description |
| --- | --- | --- |
| `inUserId` | `String` | The `SamAccountName` to look up. |
| `inResourceName` | `String` | The group `Name` to match against the user's authorization groups. |
| `inExternalDomain` | `Boolean` | Selects `external.saif.com` when `True`, `corp.saif.com` when `False`. |

| Part | Type | Description |
| --- | --- | --- |
| `<return>` | `ADServiceResponse` | `Response` is `Success` or `UserDoesNotExist`. `Message` carries the literal string `"True"` or `"False"` — the answer to the question is encoded here, not in `Response`. |

## WebMethod attributes

`<WebMethod()>` — bare, no arguments supplied.

## Steps

1. No access check is performed ([BR-06](../business-rules.md#br-06-read-only-directory-queries-are-not-access-controlled)).
2. Call H2 `GetUserPrincipal` with `inExternalDomain`.
3. Call H3 `GetGroupPrincipal` with `inExternalDomain` ([BR-33](../business-rules.md#br-33-a-group-is-resolved-by-samaccountname%2C-taking-the-first-match)) — the result is assigned to a local variable and never used (tech debt TD-23, dead code — see [Tech debt](../tech-debt.md)).
4. Initialize `Message = "False"`, `Response = Success`.
5. Write the per-request instance field `m_FoundUser = False` (never read afterward on this path).
6. If the user principal is `Nothing`, set `Response = UserDoesNotExist`.
7. Else iterate `userPrin.GetAuthorizationGroups()` and set `Message = "True"` on the first group whose `Name` equals `inResourceName`, then exit the loop ([BR-22](../business-rules.md#br-22-a-user-has-a-resource-by-exact-transitive-group-name-match)).
8. Release the user principal.
9. Return the response sentinel.

## Process flow

```mermaid
flowchart TD
    A["Call DoesUserHaveResource"] --> B["GetUserPrincipal<br>inExternalDomain"]
    B --> C["GetGroupPrincipal<br>result unused"]
    C --> D["Init Message = False<br>Response = Success"]
    D --> E["Write m_FoundUser = False"]
    E --> F{"User principal<br>found?"}
    F -->|"No"| G["Set UserDoesNotExist"]
    F -->|"Yes"| H["Iterate authorization groups<br>match Name = inResourceName"]
    H -->|"Match found"| I["Set Message = True"]
    H -->|"No match"| J["Leave Message = False"]
    G --> K["Return response"]
    I --> K
    J --> K
```

## Shared state effects

None — this operation writes the per-request instance field `m_FoundUser`, which has no cross-request effect and is not read again on this path.

## Error handling

There is **no `Try`/`Catch`** in this operation. A directory failure inside `GetAuthorizationGroups()` propagates as a framework SOAP fault. Otherwise the operation never faults, and the answer is carried as the literal string `"True"`/`"False"` in `Message`, not in `Response`. See [Faults](../faults.md) for the service-wide fault model.

## Authorization

None in code. This is one of the eleven ungated operations — see [Authentication and authorization](../authentication-authorization.md).

## Related documentation
- [Service index](../index.md)
- [Overview](../overview.md)
- [Architecture](../architecture.md)
- [Activation and hosting](../activation-hosting.md)
- [Operations](../operations.md)
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [Authentication and authorization](../authentication-authorization.md)
- [Configuration](../configuration.md)
- [Dependencies](../dependencies.md)
- [Faults](../faults.md)
- [Operational runbook](../operational-runbook.md)
- [Tech debt](../tech-debt.md)

## Sources
- `src\ADUserServices\clsADUserServices.asmx.vb` (lines 355-386)
